package com.hotacorp.opencloud.flowservice.service.impl;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.repository.ProcessDefinitionQuery;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.hotacorp.opencloud.common.mybatisplus.PageConstant;
import com.hotacorp.opencloud.common.mybatisplus.PageData;
import com.hotacorp.opencloud.flowservice.dto.ProcessInstanceRunInfo;
import com.hotacorp.opencloud.flowservice.dto.ProcessRequest;
import com.hotacorp.opencloud.flowservice.dto.TaskInfo;
import com.hotacorp.opencloud.flowservice.dto.TaskRequest;
import com.hotacorp.opencloud.flowservice.dto.TurnOverTaskRequest;
import com.hotacorp.opencloud.flowservice.service.ProcessHandler;

/**
 * 流程处理接口实现
 * @author lwg
 *
 */
@Component
public class ProcessHandlerImpl implements ProcessHandler {
	@Autowired
	private RepositoryService repositoryService;

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private TaskService taskService;

	@Autowired
	private HistoryService historyService;
	
	@Autowired
	private IdentityService identityService;

	@Override
	public String startProcess(String tenantid, String username, ProcessRequest req) {
		identityService.setAuthentication(username, null, Arrays.asList(tenantid));
		Map<String, Object> variables = new HashMap<String, Object>();
		if (req.getVariables() != null) variables.putAll(req.getVariables());
		variables.put("starter", username);
		
		ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
		query.processDefinitionKey(req.getProcessDefinitionKey());
		query.tenantIdIn(tenantid);
		query.active();
		query.orderByProcessDefinitionVersion().desc();
		List<ProcessDefinition> list = query.listPage(0, 2);
		ProcessDefinition sss = null;
		if (list != null && list.size() > 0) 
			sss = list.get(0);
		if (sss != null) {
			variables.put("definitionkey", sss.getKey());
			variables.put("flowname", sss.getName());
			ProcessInstance processInstance = runtimeService.startProcessInstanceById(sss.getId(), req.getProcessBusinessKey(), variables);
			if (processInstance != null && StringUtils.isNotBlank(processInstance.getId())) {
				System.out.println(processInstance);
//				List<Task> list = GetNeedDoTasks(processInstance.getId(), username);
//				list.forEach(action->{
//					taskService.createComment(action.getId(), processInstance.getId(), "提交流程");
//					taskService.complete(action.getId(), variables);
//				});
				identityService.clearAuthentication();
				return processInstance.getId();
			}
		}
		identityService.clearAuthentication();
		return null;
	}

//	public List<Task> GetNeedDoTasks(String processInstId, String assignid) {
//		return taskService.createTaskQuery().processInstanceId(processInstId).taskAssignee(assignid).list();
//	}

	@Override
	public boolean approveProcess(String tenantid, String username, TaskRequest req) {
		identityService.setAuthentication(username, null, Arrays.asList(tenantid));
		Task task = taskService.createTaskQuery().tenantIdIn(tenantid).taskId(req.getTaskId()).singleResult();
		if (task != null && StringUtils.equals(username, task.getAssignee())) {
			Map<String, Object> variables = new HashMap<String, Object>();
			if (req.getVariables() != null) variables.putAll(req.getVariables());
			taskService.createComment(req.getTaskId(), task.getProcessInstanceId(), "审批流程");
			taskService.complete(req.getTaskId(), variables);
			identityService.clearAuthentication();
			return true;
		} else {
			identityService.clearAuthentication();
			return false;
		}
	}

	@Override
	public boolean terminateProcess(String tenantid, String username, String processinstanceid) {
		ProcessInstance sssss = runtimeService.createProcessInstanceQuery().tenantIdIn(tenantid).processInstanceId(processinstanceid).variableValueEquals("starter", username).singleResult();
		if (sssss != null) {
			//taskService.createComment(taskid, task.getProcessInstanceId(), username + "终止、作废流程");
			runtimeService.deleteProcessInstance(processinstanceid, username + "终止、作废流程");
			return true;
		} else {
			return false;
		}
	}

	@Override
	public boolean turnOverProcess(String tenantid, String username, TurnOverTaskRequest req) {
		Task task = taskService.createTaskQuery().tenantIdIn(tenantid).taskId(req.getTaskId()).singleResult();
		if (task != null) {
			taskService.delegateTask(task.getId(), req.getNextUserName());
		    String comment = username+"将流程委托给"+req.getNextUserName()+"处理";
		    taskService.createComment(req.getTaskId(), task.getProcessInstanceId(),comment);
		    return true;
		} else {
			return false;
		}
	}

	@Override
	public PageData needDeal(String tenantid, String username, Map<String, Object> params) {
        //分页参数
        int curPage = 1;
        int limit = 10;

        if(params.get(PageConstant.PAGE) != null){
            curPage = Integer.parseInt((String)params.get(PageConstant.PAGE));
        }
        if(params.get(PageConstant.LIMIT) != null){
            limit = Integer.parseInt((String)params.get(PageConstant.LIMIT));
        }
        //排序字段
        String orderField = (String)params.get(PageConstant.PROP);
        //排序方式
        String order = (String)params.get(PageConstant.ORDER);
        
        
        
        TaskQuery query = taskService.createTaskQuery().tenantIdIn(tenantid).active().taskAssignee(username);
		if (StringUtils.isNotBlank((String)params.get("name"))) query.taskNameLike("%" + (String)params.get("name") + "%");
        //前端字段排序
        if(StringUtils.isNotBlank(orderField) && StringUtils.isNotBlank(order)){
        	if ("id".equals(orderField)) query.orderByTaskId();
        	else if ("name".equals(orderField))  query.orderByTaskName();
        	else query.orderByTaskCreateTime();
            if(PageConstant.ASC.equalsIgnoreCase(order)) {
            	query.asc();
            }else {
            	query.desc();
            }
        }
        int reccount = (int) query.count();
        List<Task> list = query.listPage((curPage-1)*limit, limit);
        List<TaskInfo> list1 = new ArrayList<>();
        list.forEach(action->{
        	
        	TaskInfo retyDeployInfo = new TaskInfo();
        	retyDeployInfo.setId(action.getId());
        	retyDeployInfo.setName(action.getName());
        	retyDeployInfo.setProcessinstanceid(action.getProcessInstanceId());
        	retyDeployInfo.setCreateTime(action.getCreateTime());
        	HistoricProcessInstance jjjHistoricProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(action.getProcessInstanceId()).singleResult();
        	retyDeployInfo.setStarter(jjjHistoricProcessInstance.getStartUserId());
        	retyDeployInfo.setDefinitionkey(jjjHistoricProcessInstance.getProcessDefinitionKey());
        	retyDeployInfo.setFlowname(jjjHistoricProcessInstance.getProcessDefinitionName());
        	retyDeployInfo.setBusinesskey(jjjHistoricProcessInstance.getBusinessKey());
        	list1.add(retyDeployInfo);
        });
		return new PageData(list1, reccount, limit, curPage);
	}

	@Override
	public int getProcessStatus(String tenantid, String username, String processinstanceid) {
		HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processinstanceid).tenantIdIn(tenantid).singleResult();
		if (instance != null) {
			if (StringUtils.equals(instance.getState(), HistoricProcessInstance.STATE_COMPLETED)) return 0;
			else if (StringUtils.equals(instance.getState(), HistoricProcessInstance.STATE_SUSPENDED)) return 1;
			else if (StringUtils.equals(instance.getState(), HistoricProcessInstance.STATE_ACTIVE)) return 2;
			else if (StringUtils.equals(instance.getState(), HistoricProcessInstance.STATE_EXTERNALLY_TERMINATED)) return 3;
			else return 3;
		}
		return 3;
	}

	@Override
	public ProcessInstanceRunInfo getProcessRunInfo(String tenantid, String username, String processinstanceid) throws Exception {
		ProcessInstance instance = runtimeService.createProcessInstanceQuery().tenantIdIn(tenantid).processInstanceId(processinstanceid).singleResult();
		if (instance != null) {
			ProcessDefinition dddd = repositoryService.getProcessDefinition(instance.getProcessDefinitionId());
			if (dddd != null) {
				InputStream inputStream = repositoryService.getResourceAsStream(dddd.getDeploymentId(), dddd.getResourceName());
				ByteArrayOutputStream result = new ByteArrayOutputStream();
				byte[] buffer = new byte[1024];
				int length;
				while ((length = inputStream.read(buffer)) != -1) {
				    result.write(buffer, 0, length);
				}
				List<Task> list = taskService.createTaskQuery().processInstanceId(processinstanceid).tenantIdIn(tenantid).list();
				List<String> idStrings  = new ArrayList<String>();
				list.forEach(action->{
					idStrings.add(action.getTaskDefinitionKey());
				});
				ProcessInstanceRunInfo asdfas = new ProcessInstanceRunInfo();
				asdfas.setRunTaskId(idStrings);
				asdfas.setBpmnxml(result.toString("UTF-8"));
				return asdfas;
			}
		}
		return null;
	}

	@Override
	public boolean suspendProcess(String tenantid, String username, String processinstanceid) {
		ProcessInstance sssss = runtimeService.createProcessInstanceQuery().active().tenantIdIn(tenantid).processInstanceId(processinstanceid).variableValueEquals("starter", username).singleResult();
		if (sssss != null) {
			runtimeService.suspendProcessInstanceById(processinstanceid);
			return true;
		} else {
			return false;
		}
	}

	@Override
	public boolean activeProcess(String tenantid, String username, String processinstanceid) {
		ProcessInstance sssss = runtimeService.createProcessInstanceQuery().suspended().tenantIdIn(tenantid).processInstanceId(processinstanceid).variableValueEquals("starter", username).singleResult();
		if (sssss != null) {
			runtimeService.activateProcessInstanceById(processinstanceid);
			return true;
		} else {
			return false;
		}
	}
}
